/**
 * @file menu.c
 * @author Quan.Shen (ctrlshift12138@gmail.com)
 * @brief 
 * @version 0.1
 * @date 2025-07-18
 * 
 * @copyright Copyright (c) 2025
 * 
 */

#include "common.h"
#include "menu.h"
#include <flash_if.h>
#include <stdio.h>


static uint32_t flash_protection;

uint32_t jump_address; // 用户应用程序起始地址
pFunction jump_to_application; // 用户应用程序入口函数指针



void SerialDownload(void);
void SerialUpload(void);
void Main_Menu(void) __attribute__((noreturn));

void Main_Menu(void)
{
    uint8_t key;
    uint8_t write_protection;

    printf("\r\n======================================================================");
    printf("\r\n=                        (C) COPYRIGHT 2025                          =");
    printf("\r\n=                                                                    =");
    printf("\r\n=  STM32F1xx In-Application Programming Application  (Version 1.0.0) =");
    printf("\r\n=                                                                    =");
    printf("\r\n=                                     By Quan.Shen                   =");
    printf("\r\n======================================================================");
    printf("\r\n\r\n");

    /* 测试将要加载用户应用程序的闪存扇区是否受到写保护 */
    if (FALSH_If_GetWriteProtectionStatus() != 0)
    {
        flash_protection = 1;
    }
    else
    {
        flash_protection = 0;
    }

    while (1)
    {
        printf("\r\n================== Main Menu ============================\r\n\n");
        printf("  Download Image To the STM32F1xx Internal Flash ------- 1\r\n\n");
        printf("  Upload Image From the STM32F1xx Internal Flash ------- 2\r\n\n");
        printf("  Execute The New Program ------------------------------ 3\r\n\n");

        if (flash_protection)
        {
            printf("  Disable Write Protection ------------------------------ 4\r\n\n");
        }
        printf("==========================================================\r\n\n");
    }
    
    key = GetKey();

    switch (key)
    {
        case 0x31: // '1'
            printf("\r\nDownload Image To the STM32F1xx Internal Flash\r\n");
            SerialDownload();
            break;
        
        case 0x32: // '2'
            printf("\r\nUpload Image From the STM32F1xx Internal Flash\r\n");
            SerialUpload();
            break;

        case 0x33: // '3'
            printf("\r\nExecute The New Program\r\n");

            /* 跳转到用户程序地址 */
            jump_address = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
            jump_to_application = (pFunction) jump_address;

            /* 设置主栈指针 */
            __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);

            /* 跳转到用户应用程序 */
            jump_to_application();
            
            break;

        case 0x34: // '4'
            if (1 == flash_protection)
            {
                printf("\r\nDisable Write Protection\r\n");
                // 调用禁用写保护函数
                write_protection = FALSH_If_DisableWriteProtection();
                switch (write_protection)
                {
                    case 0:
                        printf("\r\nWrite Protection disabled...\r\n");
                        printf("...and a System Reset will be generated to reload the new option bytes\r\n");
                        NVIC_SystemReset();
                        // break;

                    case 1:
                        printf("\r\nError: Flash write unprotection failed...\r\n");
                        break;

                    case 2:
                        printf("\r\nWrite Protection is already disabled.\r\n");
                        break;

                    default:
                        break;
                }
            }
            else
            {
                printf("\r\nWrite Protection is already disabled.\r\n");
            }
            break;

        default:
            if (0 == flash_protection)
            {
                printf("Invalid Number ! ==> The number should be either 1, 2 or 3\r");
            }
            else
            {
                printf("Invalid Number ! ==> The number should be either 1, 2 or 3\r");
            }
    }
}

/**
 * @brief 接收文件并编程
 * 
 */
void SerialDownload(void)
{
    static uint8_t tab_1024[1024];
    uint8_t number[10];
    int32_t size = 0;

    printf("Waiting for the file to be sent ... (press 'a' to abort)\n\r");
    size = Ymodem_Receive(&tab_1024[0]);
    if (size > 0)
    {
        printf("\r\nProgramming Completed Successfully!\n\r--------------------------------\r\n Name: %s", file_name);
        Int2Str(number, (uint32_t)size);
        printf("\r\n Size: %s bytes\r\n", number);
        printf(" Bytes\r\n");
        printf("---------------------------------\r\n");
    }
    else if (size == -1)
    {
        printf("\n\n\rThe image size is higher than the allowed space memory!\n\r");
    }
    else if (size == -2)
    {
        printf("\n\n\rVerification failed!\n\r");
    }
    else if (size == -3)
    {
        printf("\r\n\nAborted by user.\n\r");
    }
    else
    {
        printf("\n\rFailed to receive the file!\n\r");
    }
}

/**
 * @brief 上传文件
 * 
 */
void SerialUpload(void)
{
    uint8_t status = 0;

    printf("\n\n\rSelect Receive File\n\r");

    if (GetKey() == CRC16)
    {
        status = Ymodem_Transmit((uint8_t *)APPLICATION_ADDRESS, (const uint8_t *)"UploadFileImage.bin", (uint16_t)USER_FLASH_SIZE);

        if (status != 0)
        {
            printf("\n\rError Occurred while Transmitting File!\n\r");
        }
        else
        {
            printf("\n\rFile uploaded successfully!\n\r");
        }
    }
}
